package com.smedi.ismedi.file.core.port.adapter.restful;

import com.smedi.ismedi.file.core.application.service.FileApplicationService;
import com.smedi.ismedi.file.core.application.service.LibreOfficeService;
import com.smedi.ismedi.file.core.domain.aggregatemodel.FileInfo;
import com.smedi.ismedi.file.core.domain.aggregatemodel.SignatureCommand;
import com.smedi.ismedi.file.core.infrastructure.FileUtil;
import com.smedi.ismedi.file.core.port.adapter.service.CallOtherApiService;
import com.smedi.ismedi.file.dto.request.SignatureRequest;
import com.smedi.ismedi.file.dto.response.FileInfoResponse;
import com.smedi.ismedi.file.feign.RemoteFileFeignApi;
import com.smedi.ismedi.web.starter.common.ResponseData;
import com.smedi.ismedi.web.starter.util.DozerUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import java.util.UUID;

/**
 * @Author Jimmy
 * @Date 2021/6/1 14:49
 */
@Slf4j
@RestController
@RequiredArgsConstructor
public class FileController implements RemoteFileFeignApi {
    private final FileApplicationService fileApplicationService;
    private final LibreOfficeService libreOfficeService;
    private final CallOtherApiService callOtherApiService;

    private final DozerUtil dozerUtil;

    @Value("${fdfs.web-server-url}")
    private String fileUrl;

    @Value("${fdfs.service.address.out}")
    private String FDFS_SERVICE_ADDRESS_OUT;
    @Value("${fdfs.service.address.in}")
    private String FDFS_SERVICE_ADDRESS_IN;

    /**
     * {@inheritDoc}
     */
    @Override
    public ResponseData<FileInfoResponse> fileUpLoad(MultipartFile file) {
        FileInfo result = fileApplicationService.fileUpLoad(file);
        FileInfoResponse response = dozerUtil.convertor(result, FileInfoResponse.class);
        response.setUrlOut(String.format("%s/%s/%s", FDFS_SERVICE_ADDRESS_OUT, result.getStorageGroup(),result.getPath()));

        return new ResponseData<FileInfoResponse>().success(response);
    }

    @Override
    public ResponseData<FileInfoResponse> fileUpLoadInFile(File file) {
        FileInfo result = fileApplicationService.fileUpLoad(file);
        FileInfoResponse response = dozerUtil.convertor(result, FileInfoResponse.class);
        response.setUrlOut(String.format("%s/%s/%s", FDFS_SERVICE_ADDRESS_OUT, result.getStorageGroup(),result.getPath()));

        return new ResponseData<FileInfoResponse>().success(response);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public ResponseData<Boolean> uploadFileConfirm(String signKey) {
        boolean result = fileApplicationService.uploadFileConfirm(signKey);

        return new ResponseData<>().success(result);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public ResponseData<FileInfoResponse> getFileInfo(String signKey) {
        FileInfo file = fileApplicationService.getFileInfo(signKey);
        FileInfoResponse fileInfoResponse = dozerUtil.convertor(file, FileInfoResponse.class);
        fileInfoResponse.setUrlOut(String.format("%s/%s/%s", FDFS_SERVICE_ADDRESS_OUT, file.getStorageGroup(),file.getPath()));
        return new ResponseData<FileInfoResponse>().success(fileInfoResponse);
    }

    @Override
    public ResponseData<List<FileInfoResponse>> getFileList(List<String> signKeys) {
        List<FileInfo> files = fileApplicationService.getFileInfo(signKeys);
        List<FileInfoResponse> fileInfoResponses = dozerUtil.convertor(files, FileInfoResponse.class);
        for(FileInfoResponse fileInfoResponse:fileInfoResponses){
            fileInfoResponse.setUrlIn(FDFS_SERVICE_ADDRESS_IN + fileInfoResponse.getStorageGroup() + "/" + fileInfoResponse.getPath());
            fileInfoResponse.setUrlOut(FDFS_SERVICE_ADDRESS_OUT + fileInfoResponse.getStorageGroup() + "/" + fileInfoResponse.getPath());
        }
        return new ResponseData<FileInfoResponse>().success(fileInfoResponses);
    }

    @Override
    public ResponseData<List<FileInfoResponse>> getFileListByPost(List<String> signKeys) {
        List<FileInfo> files = fileApplicationService.getFileInfo(signKeys);
        List<FileInfoResponse> fileInfoResponses = dozerUtil.convertor(files, FileInfoResponse.class);
        for(FileInfoResponse fileInfoResponse:fileInfoResponses){
            fileInfoResponse.setUrlIn(FDFS_SERVICE_ADDRESS_IN + fileInfoResponse.getStorageGroup() + "/" + fileInfoResponse.getPath());
            fileInfoResponse.setUrlOut(FDFS_SERVICE_ADDRESS_OUT + fileInfoResponse.getStorageGroup() + "/" + fileInfoResponse.getPath());
        }
        return new ResponseData<FileInfoResponse>().success(fileInfoResponses);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public ResponseData<Boolean> deleteFileBySignKey(String signKey, String reason) {
        boolean result = fileApplicationService.deleteFileBySignKey(signKey, reason);

        return new ResponseData<>().success(result);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public ResponseData<Boolean> downloadFileBySignKey(String signKey, HttpServletResponse response) {
        boolean result = fileApplicationService.downloadFileBySignKey(signKey, response);

        return new ResponseData<>().success(result);
    }

    @Override
    public ResponseData<byte[]> downloadFileBySignKey(String signKey) throws IOException {
        return new ResponseData<>().success(fileApplicationService.downloadFileBySignKey(signKey));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public ResponseData<Boolean> downloadFile(String group, String path, String fileName, HttpServletResponse response) {
        fileApplicationService.downloadFile(group, path, fileName, response);

        return new ResponseData<>().success(true);
    }

    @Override
    public ResponseData<byte[]> downloadFile(String group, String path, String fileName) throws IOException {
        return new ResponseData<>().success(fileApplicationService.downloadFile(group, path, fileName));
    }

    /**
     * 文件转换
     *
     * @param file 需要转换的文件
     * @return ResponseEntity<byte [ ]>
     */
    @Override
    public ResponseData<FileInfoResponse> postConvertFileToPdfWithFile(MultipartFile file) {
        FileInfo fileInfoReturn = libreOfficeService.convertFileToPdfWithFile(file);
        FileInfoResponse fileInfoResponse = dozerUtil.convertor(fileInfoReturn, FileInfoResponse.class);
        fileInfoResponse.setUrlOut(String.format("%s/%s/%s", FDFS_SERVICE_ADDRESS_OUT, fileInfoReturn.getStorageGroup(),fileInfoReturn.getPath()));
        return new ResponseData<FileInfoResponse>().success(fileInfoResponse);
    }

    /**
     * key入参的文件转换
     *
     * @param fileKey 文件Key
     * @return ResponseEntity<FileInfoResponse>
     */
    @Override
    public ResponseData<FileInfoResponse> postConvertFileToPdfWithFileKey(String fileKey) {
        FileInfo fileInfo = libreOfficeService.convertFileToPdfWithFileKey(fileKey);
        FileInfoResponse response = dozerUtil.convertor(fileInfo, FileInfoResponse.class);
        response.setUrlOut(String.format("%s/%s/%s", FDFS_SERVICE_ADDRESS_OUT, fileInfo.getStorageGroup(),fileInfo.getPath()));
        return new ResponseData<FileInfoResponse>().success(response);
    }

    @Override
    public ResponseData<FileInfoResponse> postConvertFileToPdfWithFileNoSign(MultipartFile file) {
        FileInfo fileInfoReturn = libreOfficeService.convertFileToPdfWithFileNoSign(file);
        FileInfoResponse fileInfoResponse = dozerUtil.convertor(fileInfoReturn, FileInfoResponse.class);
        fileInfoResponse.setUrlOut(String.format("%s/%s/%s", FDFS_SERVICE_ADDRESS_OUT, fileInfoReturn.getStorageGroup(),fileInfoReturn.getPath()));
        return new ResponseData<FileInfoResponse>().success(fileInfoResponse);
    }

    @Override
    public ResponseData<FileInfoResponse> postConvertFileToPdfWithFileKeyNoSign(String fileKey) {
        FileInfo fileInfo = libreOfficeService.convertFileToPdfWithFileKeyNoSign(fileKey);
        FileInfoResponse response = dozerUtil.convertor(fileInfo, FileInfoResponse.class);
        response.setUrlOut(String.format("%s/%s/%s", FDFS_SERVICE_ADDRESS_OUT, fileInfo.getStorageGroup(),fileInfo.getPath()));
        return new ResponseData<FileInfoResponse>().success(response);
    }

    @Override
    public ResponseData<FileInfoResponse> postSignatures(List<SignatureRequest> signatureRequests) {
        File tempFile = null;
        URLConnection connection = null;
        String token;
        File signature;
        FileInfo fileInfo = fileApplicationService.getFileInfo(signatureRequests.get(0).getFileKey());
        String filePath = String.format("%s/%s/%s", fileUrl, fileInfo.getStorageGroup(), fileInfo.getPath());
        String tempFileName = UUID.randomUUID().toString();
        List<SignatureCommand> signatureCommands = dozerUtil.convertor(signatureRequests, SignatureCommand.class);

        try {
            tempFile = File.createTempFile(tempFileName, ".pdf");
        } catch (Exception exception) {
            log.error("临时文件创建失败{}", exception.getMessage());
        }

        try {
            URL url = new URL("http://" + filePath);
            connection = url.openConnection();
        } catch (Exception exception) {
            log.error("{}url无法打开", filePath);
        }

        assert connection != null;

        try (InputStream inputStream = connection.getInputStream()) {
            assert tempFile != null;
            FileUtils.copyInputStreamToFile(inputStream, tempFile);
        } catch (Exception exception) {
            log.error("inputStream转File失败");
        }

        try {
            token = callOtherApiService.getToken();
        } catch (Exception exception) {
            log.warn("获取签章token失败");
            FileInfoResponse response = dozerUtil.convertor(fileInfo, FileInfoResponse.class);
            return new ResponseData<>().success(response);
        }

        try {
            signature = callOtherApiService.getSignature(token, tempFile, signatureCommands);
        } catch (Exception exception) {
            log.warn("获取签章失败");
            FileInfoResponse response = dozerUtil.convertor(fileInfo, FileInfoResponse.class);
            return new ResponseData<>().success(response);
        }

        MultipartFile multipartFile = FileUtil.fileToMultipartFile(signature);
        FileInfo fileInfoReturn = fileApplicationService.fileUpLoad(multipartFile);
        FileInfoResponse response = dozerUtil.convertor(fileInfoReturn, FileInfoResponse.class);
        return new ResponseData<FileInfoResponse>().success(response);
    }

    @Override
    public ResponseData<FileInfoResponse> postConvertFileToPdfWithFileNoFree(MultipartFile file) {
        FileInfo fileInfoReturn = libreOfficeService.convertFileToPdfWithFileNoFree(file);
        FileInfoResponse fileInfoResponse = dozerUtil.convertor(fileInfoReturn, FileInfoResponse.class);
        fileInfoResponse.setUrlOut(String.format("%s/%s/%s", FDFS_SERVICE_ADDRESS_OUT, fileInfoReturn.getStorageGroup(),fileInfoReturn.getPath()));
        return new ResponseData<FileInfoResponse>().success(fileInfoResponse);
    }

    @Override
    public ResponseData<FileInfoResponse> postConvertFileToPdfWithFileKeyNoFree(String fileKey) {
        FileInfo fileInfoReturn = libreOfficeService.convertFileToPdfWithFileKeyNoSign(fileKey);
        FileInfoResponse fileInfoResponse = dozerUtil.convertor(fileInfoReturn, FileInfoResponse.class);
        fileInfoResponse.setUrlOut(String.format("%s/%s/%s", FDFS_SERVICE_ADDRESS_OUT, fileInfoReturn.getStorageGroup(),fileInfoReturn.getPath()));
        return new ResponseData<FileInfoResponse>().success(fileInfoResponse);
    }

    @Override
    public ResponseData<FileInfoResponse> postZipBySignKeys(List<String> fileKeys) throws IOException {
        fileApplicationService.zipBySignKeys(fileKeys);
        return null;
    }

    @Override
    public ResponseData<FileInfoResponse> pdfMerge(List<String> signKeys) throws IOException {
        FileInfo fileInfo = fileApplicationService.pdfMerge(signKeys);
        return new ResponseData<>().success(dozerUtil.convertor(fileInfo,FileInfoResponse.class));
    }
}

